"""
工具函数模块

提供重试、错误处理和其他通用工具函数
"""

import asyncio
import functools
import time
from typing import Any, Callable, Optional, Union, Dict, List
import logging
import random

from .unified_core import unified_logger


def retry(max_attempts: int = 3, delay: float = 1.0, backoff_factor: float = 2.0,
          exceptions: tuple = (Exception,), logger: Optional[logging.Logger] = None,
          jitter: bool = True, condition: Optional[Callable[[Exception], bool]] = None):
    """
    增强的重试装饰器
    
    Args:
        max_attempts: 最大重试次数
        delay: 初始延迟时间（秒）
        backoff_factor: 退避因子
        exceptions: 需要重试的异常类型
        logger: 日志记录器
        jitter: 是否添加随机抖动
        condition: 额外的重试条件函数
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        async def async_wrapper(*args, **kwargs) -> Any:
            _logger = logger or unified_logger.get_logger(func.__module__)
            last_exception = None
            
            for attempt in range(max_attempts):
                try:
                    if asyncio.iscoroutinefunction(func):
                        return await func(*args, **kwargs)
                    else:
                        return func(*args, **kwargs)
                except exceptions as e:
                    last_exception = e
                    
                    # 检查额外的重试条件
                    if condition and not condition(e):
                        _logger.info(f"重试条件不满足，停止重试: {e}")
                        raise
                    
                    if attempt == max_attempts - 1:
                        _logger.error(f"重试失败，已达到最大重试次数 {max_attempts}: {e}")
                        raise
                    
                    wait_time = delay * (backoff_factor ** attempt)
                    
                    # 添加随机抖动
                    if jitter:
                        wait_time *= (0.5 + random.random())
                    
                    _logger.warning(f"第 {attempt + 1} 次重试失败: {e}，{wait_time:.2f}秒后重试")
                    await asyncio.sleep(wait_time)
            
            # 如果所有重试都失败，抛出最后一个异常
            if last_exception:
                raise last_exception
            
        @functools.wraps(func)
        def sync_wrapper(*args, **kwargs) -> Any:
            _logger = logger or unified_logger.get_logger(func.__module__)
            last_exception = None
            
            for attempt in range(max_attempts):
                try:
                    return func(*args, **kwargs)
                except exceptions as e:
                    last_exception = e
                    
                    # 检查额外的重试条件
                    if condition and not condition(e):
                        _logger.info(f"重试条件不满足，停止重试: {e}")
                        raise
                    
                    if attempt == max_attempts - 1:
                        _logger.error(f"重试失败，已达到最大重试次数 {max_attempts}: {e}")
                        raise
                    
                    wait_time = delay * (backoff_factor ** attempt)
                    
                    # 添加随机抖动
                    if jitter:
                        wait_time *= (0.5 + random.random())
                    
                    _logger.warning(f"第 {attempt + 1} 次重试失败: {e}，{wait_time:.2f}秒后重试")
                    time.sleep(wait_time)
            
            # 如果所有重试都失败，抛出最后一个异常
            if last_exception:
                raise last_exception
        
        if asyncio.iscoroutinefunction(func):
            return async_wrapper
        else:
            return sync_wrapper
    
    return decorator


def smart_retry(func: Callable = None, *, 
                network_errors: int = 3,
                api_errors: int = 2, 
                data_errors: int = 2,
                other_errors: int = 1):
    """
    智能重试装饰器，根据错误类型使用不同的重试策略
    
    Args:
        network_errors: 网络错误重试次数
        api_errors: API错误重试次数
        data_errors: 数据错误重试次数
        other_errors: 其他错误重试次数
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        async def async_wrapper(*args, **kwargs) -> Any:
            _logger = unified_logger.get_logger(func.__module__)
            
            # 根据错误类型确定重试策略
            def get_retry_config(error: Exception) -> tuple:
                error_name = type(error).__name__
                
                if any(keyword in error_name.lower() for keyword in ['network', 'connection', 'timeout']):
                    return network_errors, 1.0, 2.0
                elif any(keyword in error_name.lower() for keyword in ['api', 'http', 'request']):
                    return api_errors, 0.5, 1.5
                elif any(keyword in error_name.lower() for keyword in ['data', 'parse', 'format']):
                    return data_errors, 0.2, 1.2
                else:
                    return other_errors, 0.1, 1.0
            
            last_exception = None
            total_attempts = 0
            
            while total_attempts < max(network_errors, api_errors, data_errors, other_errors):
                try:
                    if asyncio.iscoroutinefunction(func):
                        return await func(*args, **kwargs)
                    else:
                        return func(*args, **kwargs)
                except Exception as e:
                    last_exception = e
                    max_attempts, delay, backoff = get_retry_config(e)
                    
                    if total_attempts >= max_attempts:
                        _logger.error(f"智能重试失败: {e}")
                        raise
                    
                    wait_time = delay * (backoff ** total_attempts)
                    wait_time *= (0.5 + random.random())  # 添加抖动
                    
                    _logger.warning(f"智能重试 ({type(e).__name__}): 第 {total_attempts + 1} 次，{wait_time:.2f}秒后重试")
                    await asyncio.sleep(wait_time)
                    total_attempts += 1
            
            if last_exception:
                raise last_exception
        
        @functools.wraps(func)
        def sync_wrapper(*args, **kwargs) -> Any:
            _logger = unified_logger.get_logger(func.__module__)
            
            # 根据错误类型确定重试策略
            def get_retry_config(error: Exception) -> tuple:
                error_name = type(error).__name__
                
                if any(keyword in error_name.lower() for keyword in ['network', 'connection', 'timeout']):
                    return network_errors, 1.0, 2.0
                elif any(keyword in error_name.lower() for keyword in ['api', 'http', 'request']):
                    return api_errors, 0.5, 1.5
                elif any(keyword in error_name.lower() for keyword in ['data', 'parse', 'format']):
                    return data_errors, 0.2, 1.2
                else:
                    return other_errors, 0.1, 1.0
            
            last_exception = None
            total_attempts = 0
            
            while total_attempts < max(network_errors, api_errors, data_errors, other_errors):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    last_exception = e
                    max_attempts, delay, backoff = get_retry_config(e)
                    
                    if total_attempts >= max_attempts:
                        _logger.error(f"智能重试失败: {e}")
                        raise
                    
                    wait_time = delay * (backoff ** total_attempts)
                    wait_time *= (0.5 + random.random())  # 添加抖动
                    
                    _logger.warning(f"智能重试 ({type(e).__name__}): 第 {total_attempts + 1} 次，{wait_time:.2f}秒后重试")
                    time.sleep(wait_time)
                    total_attempts += 1
            
            if last_exception:
                raise last_exception
        
        if asyncio.iscoroutinefunction(func):
            return async_wrapper
        else:
            return sync_wrapper
    
    if func is None:
        return decorator
    else:
        return decorator(func)


def timeout(seconds: float):
    """
    超时装饰器
    
    Args:
        seconds: 超时时间（秒）
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        async def async_wrapper(*args, **kwargs) -> Any:
            try:
                return await asyncio.wait_for(func(*args, **kwargs), timeout=seconds)
            except asyncio.TimeoutError:
                raise TimeoutError(f"函数 {func.__name__} 执行超时 ({seconds}秒)")
        
        @functools.wraps(func)
        def sync_wrapper(*args, **kwargs) -> Any:
            # 对于同步函数，使用信号实现超时（仅限Unix系统）
            import signal
            
            def timeout_handler(signum, frame):
                raise TimeoutError(f"函数 {func.__name__} 执行超时 ({seconds}秒)")
            
            # 设置信号处理器
            old_handler = signal.signal(signal.SIGALRM, timeout_handler)
            signal.alarm(int(seconds))
            
            try:
                result = func(*args, **kwargs)
                signal.alarm(0)  # 取消定时器
                return result
            finally:
                signal.signal(signal.SIGALRM, old_handler)
        
        if asyncio.iscoroutinefunction(func):
            return async_wrapper
        else:
            return sync_wrapper
    
    return decorator


def rate_limit(calls_per_second: float):
    """
    速率限制装饰器
    
    Args:
        calls_per_second: 每秒允许的调用次数
    """
    min_interval = 1.0 / calls_per_second
    last_called = [0.0]
    
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        async def async_wrapper(*args, **kwargs) -> Any:
            now = time.time()
            elapsed = now - last_called[0]
            
            if elapsed < min_interval:
                sleep_time = min_interval - elapsed
                await asyncio.sleep(sleep_time)
            
            last_called[0] = time.time()
            return await func(*args, **kwargs)
        
        @functools.wraps(func)
        def sync_wrapper(*args, **kwargs) -> Any:
            now = time.time()
            elapsed = now - last_called[0]
            
            if elapsed < min_interval:
                sleep_time = min_interval - elapsed
                time.sleep(sleep_time)
            
            last_called[0] = time.time()
            return func(*args, **kwargs)
        
        if asyncio.iscoroutinefunction(func):
            return async_wrapper
        else:
            return sync_wrapper
    
    return decorator


def cache_result(ttl_seconds: int = 300):
    """
    结果缓存装饰器
    
    Args:
        ttl_seconds: 缓存生存时间（秒）
    """
    cache = {}
    
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        async def async_wrapper(*args, **kwargs) -> Any:
            # 创建缓存键
            cache_key = str(args) + str(sorted(kwargs.items()))
            now = time.time()
            
            # 检查缓存
            if cache_key in cache:
                result, timestamp = cache[cache_key]
                if now - timestamp < ttl_seconds:
                    return result
                else:
                    del cache[cache_key]
            
            # 执行函数并缓存结果
            result = await func(*args, **kwargs)
            cache[cache_key] = (result, now)
            return result
        
        @functools.wraps(func)
        def sync_wrapper(*args, **kwargs) -> Any:
            # 创建缓存键
            cache_key = str(args) + str(sorted(kwargs.items()))
            now = time.time()
            
            # 检查缓存
            if cache_key in cache:
                result, timestamp = cache[cache_key]
                if now - timestamp < ttl_seconds:
                    return result
                else:
                    del cache[cache_key]
            
            # 执行函数并缓存结果
            result = func(*args, **kwargs)
            cache[cache_key] = (result, now)
            return result
        
        if asyncio.iscoroutinefunction(func):
            return async_wrapper
        else:
            return sync_wrapper
    
    return decorator


def safe_execute(func: Callable, *args, default=None, logger: Optional[logging.Logger] = None, **kwargs):
    """
    安全执行函数，捕获异常并返回默认值
    
    Args:
        func: 要执行的函数
        *args: 函数参数
        default: 异常时返回的默认值
        logger: 日志记录器
        **kwargs: 函数关键字参数
    """
    _logger = logger or unified_logger.get_logger(__name__)
    
    try:
        return func(*args, **kwargs)
    except Exception as e:
        _logger.error(f"安全执行失败: {func.__name__}, 错误: {e}")
        return default


async def safe_execute_async(func: Callable, *args, default=None, logger: Optional[logging.Logger] = None, **kwargs):
    """
    安全执行异步函数，捕获异常并返回默认值
    
    Args:
        func: 要执行的异步函数
        *args: 函数参数
        default: 异常时返回的默认值
        logger: 日志记录器
        **kwargs: 函数关键字参数
    """
    _logger = logger or unified_logger.get_logger(__name__)
    
    try:
        return await func(*args, **kwargs)
    except Exception as e:
        _logger.error(f"安全执行失败: {func.__name__}, 错误: {e}")
        return default


def validate_params(**validators):
    """
    参数验证装饰器
    
    Args:
        **validators: 参数验证器字典，键为参数名，值为验证函数
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 获取函数签名
            import inspect
            sig = inspect.signature(func)
            bound_args = sig.bind(*args, **kwargs)
            bound_args.apply_defaults()
            
            # 验证参数
            for param_name, validator in validators.items():
                if param_name in bound_args.arguments:
                    value = bound_args.arguments[param_name]
                    if not validator(value):
                        raise ValueError(f"参数 {param_name} 验证失败: {value}")
            
            return func(*args, **kwargs)
        
        return wrapper
    
    return decorator


def measure_time(logger: Optional[logging.Logger] = None):
    """
    执行时间测量装饰器
    
    Args:
        logger: 日志记录器
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        async def async_wrapper(*args, **kwargs) -> Any:
            _logger = logger or unified_logger.get_logger(func.__module__)
            start_time = time.time()
            
            try:
                result = await func(*args, **kwargs)
                execution_time = time.time() - start_time
                _logger.info(f"{func.__name__} 执行时间: {execution_time:.3f}秒")
                return result
            except Exception as e:
                execution_time = time.time() - start_time
                _logger.error(f"{func.__name__} 执行失败 (耗时: {execution_time:.3f}秒): {e}")
                raise
        
        @functools.wraps(func)
        def sync_wrapper(*args, **kwargs) -> Any:
            _logger = logger or unified_logger.get_logger(func.__module__)
            start_time = time.time()
            
            try:
                result = func(*args, **kwargs)
                execution_time = time.time() - start_time
                _logger.info(f"{func.__name__} 执行时间: {execution_time:.3f}秒")
                return result
            except Exception as e:
                execution_time = time.time() - start_time
                _logger.error(f"{func.__name__} 执行失败 (耗时: {execution_time:.3f}秒): {e}")
                raise
        
        if asyncio.iscoroutinefunction(func):
            return async_wrapper
        else:
            return sync_wrapper
    
    return decorator